Skip to content

Restore static linking of the C++ runtime for Windows wheels - #526

Merged
jamadden merged 1 commit into
python-greenlet:masterfrom
stickerdaniel:windows-static-runtime
Aug 10, 2026
Merged

Restore static linking of the C++ runtime for Windows wheels#526
jamadden merged 1 commit into
python-greenlet:masterfrom
stickerdaniel:windows-static-runtime

Conversation

@stickerdaniel

Copy link
Copy Markdown
Contributor

appveyor.yml set GREENLET_STATIC_RUNTIME: "1" and setup.py still honours it by adding /MT. #490 removed that file when the Windows builds moved to GHA, and the step that replaced it does not set the variable, so every Windows wheel since 3.3.1 links the C++ runtime dynamically and imports MSVCP140.dll. No Windows CPython distribution ships that DLL, so greenlet fails to import on machines without the Visual C++ redistributable.

Setting the variable in the step that builds the published Windows wheels restores the behaviour of 3.3.0 and earlier. setup.py guards it with is_win, so the Linux build in the same step is unaffected, and the Windows ARM wheels that #490 added keep being produced.

Fixes #525

The Appveyor builds set GREENLET_STATIC_RUNTIME; the GHA step that
replaced them does not, so every Windows wheel since 3.3.1 imports
MSVCP140.dll, which no Windows CPython distribution ships.

Fixes: python-greenlet#525
Copilot AI lite review requested due to automatic review settings August 8, 2026 13:05

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@stickerdaniel

Copy link
Copy Markdown
Contributor Author

CI is green on all Windows jobs. Reading the import table of the wheels this run produced:

greenlet-3.5.5.dev0-cp312-cp312-win_amd64.whl
    KERNEL32.dll, python312.dll
greenlet-3.5.5.dev0-cp312-cp312-win_arm64.whl
    KERNEL32.dll, python312.dll

No MSVCP140.dll and no VCRUNTIME140*, matching 3.3.0 and earlier. The ARM64 wheels behave the same, which Appveyor never covered.

stickerdaniel added a commit to stickerdaniel/linkedin-mcp-server that referenced this pull request Aug 9, 2026
Closes #697

On Windows the server can exit before it starts, with an `ImportError` about `_greenlet` and a DLL that is never named. greenlet moved its Windows builds from Appveyor to GitHub Actions in 3.3.1 and lost the `GREENLET_STATIC_RUNTIME` flag on the way, so `_greenlet.pyd` links the C++ runtime dynamically and needs `MSVCP140.dll`. That DLL comes with the Visual C++ redistributable and no Python distribution ships it, so a machine without the redistributable cannot load greenlet at all. We never call greenlet ourselves; patchright imports it unconditionally on the async-only path, which is why the failure lands before any of our code runs.

The probe lives in the package `__init__` because that is the only place both entry paths reach before `cli_main` pulls in patchright, and it costs nothing on the path that matters since patchright imports the same module moments later. It runs on Windows only. It matches on `DLL load failed`, a prefix CPython formats itself in `dynload_win.c` and keeps English on every install, and re-raises anything else untouched so a merely absent greenlet is not handed advice about a redistributable. The message names both routes, because installing the redistributable needs administrator rights that a `uvx` user may not have, and the stopgap it offers is marked x86-64 only since there are no Windows ARM64 wheels before 3.3.1. Two README troubleshooting sections gain the same pointer.

The upstream fix is filed as python-greenlet/greenlet#525 with the one-line restore in python-greenlet/greenlet#526, where CI now builds x64 and ARM64 wheels that import nothing beyond `KERNEL32.dll` and the Python DLL again. That does not retire this guard: the affected wheels stay on PyPI, and any resolver landing on one reproduces the failure.

Eight tests cover the translated message, the preserved cause, the re-raise, the platform gate and the import ordering, and they run on every platform because the reasoning about a Windows failure should not need a Windows machine; full suite green.

See also: #688

## Synthetic prompt

> On Windows without the Visual C++ redistributable the server dies at import with `DLL load failed while importing _greenlet`, because greenlet's wheels stopped linking the C++ runtime statically in 3.3.1. Add a Windows-only startup probe that turns that bare ImportError into a message naming `MSVCP140.dll` and the redistributable, with a stopgap for machines without admin rights. Put it where both entry paths reach it before patchright is imported, keep the detection locale-independent, re-raise unrelated import failures unchanged, and add README troubleshooting entries plus tests that run on every platform.

Generated with Claude Opus 5 high + Sol 5.6 xhigh
@jamadden

Copy link
Copy Markdown
Contributor

Thanks for the diagnosis and quick fix!

@jamadden
jamadden merged commit f3746aa into python-greenlet:master Aug 10, 2026
39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows wheels since 3.3.1 require the Visual C++ redistributable

3 participants